﻿using System;
using System.Drawing;
using System.Text;

using Storm.TextEditor.Parser.Objects;

namespace Storm.TextEditor.Editor.Exporters
{
	/// <summary>
	/// Represents an exporter that exports text of a document to an Html webpage.
	/// </summary>
	public class HtmlExporter
	{
		#region Fields

		private StringBuilder stringBuilder = null;

		#endregion

		#region Methods

		#region Public

		/// <summary>
		/// Exports the content of a SyntaxDocument to a HTML formatted string.
		/// </summary>
		/// <param name="document">SyntaxDocument object to export from.</param>
		/// <param name="imagePath">File path to the images to use in the HTML string.</param>
		/// <returns>The text of the given SyntaxDocument as HTML source code.</returns>
		public string Export(SyntaxDocument document, string imagePath)
		{
			return Export(document, Color.Transparent, imagePath, "");
		}

		/// <summary>
		/// Exports the content of a SyntaxDocument to a HTML formatted string.
		/// </summary>
		/// <param name="document">SyntaxDocument object to export from.</param>
		/// <param name="backColor">HTML color string to use as background color.</param>
		/// <param name="imagePath">File path to the images to use in the HTML string.</param>
		/// <param name="style">HTML style string that should be applied to the output.</param>
		/// <returns>The text of the given SyntaxDocument as HTML source code.</returns>
		public string Export(SyntaxDocument document, Color backColor, string imagePath, string style)
		{
			stringBuilder = new StringBuilder();
			document.ParseAll(true);

			int    index = 0;
			string guid  = DateTime.Now.Ticks.ToString();

			if (backColor.A == 0)
				this.Out("<table><tr><td nowrap><div style=\"" + style + "\">");
			else
				this.Out("<table style=\"background-color:" + this.GetHtmlColor(backColor)
					+ ";" + style + "\"><tr><td nowrap><div>");

			foreach (Row row in document)
			{
				index++;
				if (row.CanFold == true)
				{
					this.RenderCollapsed(row.VirtualCollapsedRow, row, index, imagePath, guid);
					this.Out("<div style=\"display:block;\" id=\"open" + guid + "_"
						+ index.ToString() + "\">");

					string minusImagePath = "minus.gif";
					try
					{
						if (row.ExpansionStartSegment.Parent.Parent == null)
							minusImagePath = "minusNoTopLine.gif";
					}
					catch
					{
					}

					this.Out("<img src=\"" + imagePath + minusImagePath + "\" align=top onclick=\"open" + guid + "_" + index.ToString() + 
						".style.display='none'; closed" + guid + "_" + index.ToString() + ".style.display='block'; \">");
				}
				else
				{
					if (row.CanFoldEndPart == true)
						this.Out("<img src=\"" + imagePath + "L.gif\"  align=top>");
					else
					{
						if (row.HasExpansionLine == true)
							this.Out("<img src=\"" + imagePath + "I.gif\"  align=top>");
						else
							this.Out("<img src=\"" + imagePath + "clear.gif\"  align=top>");
					}
				}

				foreach (Word word in row)
					this.Write(word.Text, word.Style);

				if (row.CanFoldEndPart == true)
					this.Out("</div>\n");
				else
					this.Out("<br>\n");
			}

			this.Out("</div></td></tr></table>");
			return stringBuilder.ToString();
		}

		#endregion

		#region Private

		/// <summary>
		/// Renders the given Row as if it were collapsed.
		/// </summary>
		/// <param name="row">Row to render as collapsed.</param>
		/// <param name="trueRow">The true Row.</param>
		/// <param name="index">Index of the Row.</param>
		/// <param name="imagePath">Path to the image to use for the rendering.</param>
		/// <param name="guid">GUID.</param>
		private void RenderCollapsed(Row row, Row trueRow, int index, string imagePath, string guid)
		{
			this.Out("<div style=\"display:none;\" id=\"closed" + guid + "_" + index.ToString() + "\">");

			string plusImagePath = "plus.gif";
			try
			{
				if (trueRow.ExpansionStartSegment.Parent.Parent == null)
					plusImagePath = "PlusNoLines.gif";
			}
			catch
			{
			}

			this.Out("<img src=\"" + imagePath + plusImagePath + "\" align=top onclick=\"open" + guid + "_" + index.ToString() + 
				".style.display='block'; closed" + guid + "_" + index.ToString() + ".style.display='none'; \">");

			foreach (Word word in row)
				this.Write(word.Text, word.Style);

			this.Out("</div>");
		}

		/// <summary>
		/// Writes the given text to the StringBuilder using the given TextStyle.
		/// </summary>
		/// <param name="text">Text to write.</param>
		/// <param name="textStyle">TextStyle to use.</param>
		private void Write(string text, TextStyle textStyle)
		{
			if (textStyle != null)
			{
				if (textStyle.Bold == true)
					this.Out("<b>");

				if (textStyle.Italic == true)
					this.Out("<i>");

				if (textStyle.Transparent == true)
					this.Out("<span style=\"color:" + this.GetHtmlColor(textStyle.ForeColor) + "\">");
				else
				{
					this.Out("<span style=\"color:" + this.GetHtmlColor(textStyle.ForeColor) + ";background-color:" +
						this.GetHtmlColor(textStyle.BackColor) + ";\">");
				}
			}

			text = text.Replace("&", "&amp;");
			text = text.Replace("<", "&lt;");
			text = text.Replace(">", "&gt;");
			text = text.Replace(" ", "&nbsp;");
			text = text.Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
			this.Out(text);

			if (textStyle != null)
			{
				this.Out("</span>");
				if (textStyle.Italic == true)
					this.Out("</i>");

				if (textStyle.Bold == true)
					this.Out("</b>");
			}
		}

		/// <summary>
		/// Returns the given color as an Html color.
		/// </summary>
		/// <param name="color">Color to convert.</param>
		/// <returns>The given color as an Html color.</returns>
		private string GetHtmlColor(Color color)
		{
			return string.Format("#{0}{1}{2}", color.R.ToString("x2"), color.G.ToString("x2"), color.B.ToString("x2"));
		}

		/// <summary>
		/// Appends the given text to the StringBuilder of the HtmlExporter.
		/// </summary>
		/// <param name="text">Text to append to the StringBuilder.</param>
		private void Out(string text)
		{
			stringBuilder.Append(text);
		}

		#endregion

		#endregion

		/// <summary>
		/// Initializes a new instance of HtmlExporter.
		/// </summary>
		public HtmlExporter()
		{
		}
	}
}
